package lt.mii.optimum.data;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import lt.mii.optimum.components.Group;
import lt.mii.optimum.components.Student;
import lt.mii.optimum.components.Subject;
import lt.mii.optimum.components.Teacher;
import lt.mii.optimum.io.XmlReadData;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Class used to centralize data storage.<br>
 * All working information on Studets, Teachers and Subjects is stored here.
 * 
 * @author dstrukov
 * 
 */
public class Data {
	private Set<Student> students;

	private List<Subject> subjects;

	private Set<Teacher> teachers;



	/**
	 * Constructor <br>
	 * Initializes storage.
	 */
	public Data() {

		String userDir = System.getProperty("user.dir");
		teachers = new HashSet<Teacher>();
		students = new HashSet<Student>();
		subjects = new ArrayList<Subject>();

		XmlReadData reader = new XmlReadData(userDir+"\\adidelis(3).xml");
		ReadSubjects(reader);
		ReadTeachers(reader);
		ReadStudents(reader);
	}



	/**
	 * Add Student to data bank
	 * 
	 * @param s -
	 *            Student to add.
	 */
	public void addStudent(Student s) {
		students.add(s);
	}



	/**
	 * Add Subject to data bank
	 * 
	 * @param s -
	 *            Subject to add.
	 */
	public void addSubject(Subject s) {
		subjects.add(s);
	}



	/**
	 * Add Teacher to data bank
	 * 
	 * @param s -
	 *            Teacher to add.
	 */
	public boolean addTeacher(Teacher s) {
		return teachers.add(s);
	}



	/**
	 * 
	 * @return Set of all Students in data bank
	 */
	public Set<Student> getStudents() {
		return students;
	}



	/**
	 * 
	 * @param index
	 *            Subjects index to return
	 * @return Subject from the list
	 */
	public Subject getSubject(int index) {
		return subjects.get(index);
	}



	/**
	 * 
	 * @return list of all Subjects in data bank
	 */
	public List<Subject> getSubjects() {
		return subjects;
	}



	/**
	 * 
	 * @return Set of all teachers in data bank
	 */
	public Set<Teacher> getTeachers() {
		return teachers;
	}



	/**
	 * Adds the Set of Students to data bank.
	 * 
	 * @param students
	 *            Set of students to place in data bank
	 */
	public void setStudents(Set<Student> students) {
		this.students.addAll(students);
	}



	/**
	 * Adds the Set of Subjects to data bank.
	 * 
	 * @param students
	 *            Set of subjects to place in data bank
	 */
	public void setSubjects(List<Subject> subjects) {
		this.subjects.addAll(subjects);
	}



	/**
	 * Adds the Set of teachers to data bank.
	 * 
	 * @param students
	 *            Set of teachers to place in data bank
	 */
	public void setTeachers(Set<Teacher> teachers) {
		this.teachers.addAll(teachers);
	}



	/**
	 * Prints out student debug information on particular subject<br>
	 * Format is: klass1, klass1, klass2 ... , # <br>
	 * (list of classes) , total of students <br>
	 * Students that need to follow given subject
	 * 
	 * @param subj
	 *            Subject to debug on.
	 */
	public void Test(Subject subj) {
		Iterator<Student> it = students.iterator();
		Set<String> temp = new HashSet<String>();
		int count = 0;
		while (it.hasNext()) {

			Student stud;
			if ((stud = it.next()).needsToStudy(subj)) {
				count++;
				temp.add(stud.getGroup().getName());
			}
			// System.out.print(" " + count + " ,");

		}

		System.out.print(temp + " " + count + "  ");
	}



	/**
	 * Prints out teacher debug information on particular subject<br>
	 * Format is: name1, name2, name3 ... , # <br>
	 * (list of teachers) , total of teachers <br>
	 * Teachers that are able to teach given subject
	 * 
	 * @param subj
	 *            Subject to debug on.
	 */
	public void TestT(Subject subj) {
		Iterator<Teacher> it = teachers.iterator();

		int count = 0;
		while (it.hasNext()) {
			Teacher stud;
			if ((stud = it.next()).canTeach(subj)) {
				count++;
				System.out.print(" " + stud.getName() + " "
						+ stud.getHours(subj) + ",");
			}
		}

		System.out.println(count);
	}



	/**
	 * Reads All Students from provided Xml Reader <br>
	 * Can not Be Executed before Subjects are read
	 * 
	 * @param reader
	 *            {@link  XmlReadData} object pointing to Initial Data File
	 */
	public void ReadStudents(XmlReadData reader) {
		// XmlReadData xml = new XmlReadData(Path);
		int studentCount = 0;

		for (int i = 0; i < reader.getSheet_count() - 3; i++) {
			studentCount += reader.getRow_count(i + 2) - 2;
		}

		int count = 0;
		for (int j = 2; j < reader.getSheet_count() - 1; j++) {
			Group klass = new Group(reader.getName(j));

			for (int i = 0; i < reader.getRow_count(j); i++) {

				Node n = reader.getData(j).item(i);
				Element row = (Element) n;

				if (i > 1) {
					Student temp = new Student();
					temp.setGroup(klass);
					// temp.setKlass(klass);
					// students[j-2][i-2] = new
					// String[read.getColumn_count()];
					NodeList cells = row.getElementsByTagName("Cell");

					for (int k = 0; k < cells.getLength(); k++) {
						boolean flag = true;
						Node list = null;
						try {
							list = cells.item(k).getChildNodes().item(0)
									.getFirstChild();

						} catch (NullPointerException ex) {
							flag = false;
						}

						if (k == 0) {
							if (flag) {
								temp.setId(new Long(list.getNodeValue()));
							} else {

							}
						} else if (k == 1) {
							if (flag) {
								temp.setName(list.getNodeValue());
							} else {
								temp.setName("null");
							}
						} else if (k < 29) {
							Subject subj = this.getSubject(k - 2);
							Integer value = Integer.parseInt(list
									.getNodeValue());
							if (flag) {
								temp.setHours(subj, value);
							} else {
								temp.setHours(subj, 0);
							}
						}

					}
					count++;
					this.addStudent(temp);
				}

			}

		}

	}



	/**
	 * Reads All Subjects from provided Xml Reader <br>
	 * Has to be executed before other reads.
	 * 
	 * @param reader
	 *            {@link  XmlReadData} object pointing to Initial Data File
	 */
	public void ReadSubjects(XmlReadData reader) {

		int rowCount = reader.getRow_count(0);

		for (int i = 0; i < rowCount; i++) {
			Node n = reader.getData(0).item(i);
			Element eilute = (Element) n;
			if (i > 0) {
				NodeList cells = eilute.getElementsByTagName("Cell");
				if (cells.getLength() <= 1)
					continue;
				Subject temp = new Subject();
				for (int k = 0; k < cells.getLength(); k++) {
					NodeList d = eilute.getElementsByTagName("Data");
					Node duom = d.item(k);
					if (duom == null)
						continue;
					Node nnn = duom.getFirstChild();

					if (k == 0) {
						String code = nnn.getNodeValue();

						temp.setSubjCode(code.trim().toUpperCase());

					} else if (k == 1) {
						String type = nnn.getNodeValue();
						temp.setPriority(Integer.parseInt(type));
					}

				}

				this.addSubject(temp);
			}
		}
		return;
	}



	/**
	 * Reads All Teachers from provided Xml Reader <br>
	 * Can not be used before Subjects are read
	 * 
	 * @param reader
	 *            {@link  XmlReadData} object pointing to Initial Data File
	 */
	public void ReadTeachers(XmlReadData reader) {

		for (int i = 0; i < reader.getRow_count(1); i++) {
			Node n = reader.getData(1).item(i);
			Element eilute = (Element) n;

			if (i > 1) {
				NodeList cells = eilute.getElementsByTagName("Cell");
				Teacher temp = new Teacher();
				for (int k = 0; k < cells.getLength(); k++) {
					Node nnn;
					try {
						nnn = cells.item(k).getChildNodes().item(0)
								.getFirstChild();

					} catch (NullPointerException ex) {
						nnn = null;
					}

					if (k == 3) {
						if (nnn != null)
							temp.setName("" + nnn.getNodeValue());
					} else if (k == 7) {
						if (nnn != null) {

							String[] values = nnn.getNodeValue().split(";");
							assert values != null;
							Set<Group> set = new HashSet<Group>();
							for (String value : values) {
								String testVal = value.trim().toUpperCase();
								if (!testVal.equals(""))
									set.add(new Group(testVal));
								else {
									// System.out.println(temp + " " + set);
								}

							}
							temp.setGroups(temp.getSubjects().get(0), set);

							// teachers[i -
							// 2].setClassGrops(classes);
						}
						// System.out.println(teachers[i-2].getHours()+"
						// k
						// ="+k);
					} else if (k == 5) {
						if (nnn != null) {
							String code = nnn.getNodeValue();
							String testCode = code.trim().toUpperCase();
							if (!testCode.equals(""))
								temp.addSubject(new Subject(testCode));

						}
					} else if (k == 6) {

						if (nnn != null) {

							temp.setHours(temp.getSubjects().get(0), Integer
									.parseInt(nnn.getNodeValue().replaceAll(
											";", "")));

						}
					} else if (k == 8) {
						if (nnn != null) {
							String tempa[] = nnn.getNodeValue().split(";");

							for (int z = 0; z < tempa.length; z++) {
								temp.addDayOff(Integer.parseInt(tempa[z]));
							}
						}

					}
				}
				if (temp == null)
					return;
				if (temp.getName() == null)
					return;
				if (!this.addTeacher(temp)) {
					Iterator<Teacher> it = this.getTeachers().iterator();
					while (it.hasNext()) {
						Teacher exist;
						if ((exist = it.next()).equals(temp)) {
							exist.merge(temp);
							// System.out.println(exist);
						}
					}
				}
			}
		}

	}
}
